package com.mrdeer.security;

import com.mrdeer.common.tools.RedisTemplateHelper;
import com.mrdeer.config.properties.AppTokenProperties;
import com.mrdeer.config.properties.IgnoredUrlsProperties;
import com.mrdeer.config.properties.TokenProperties;
import com.mrdeer.security.jwt.AuthenticationFailHandler;
import com.mrdeer.security.jwt.AuthenticationSuccessHandler;
import com.mrdeer.security.jwt.JWTAuthenticationFilter;
import com.mrdeer.security.jwt.RestAccessDeniedHandler;
import com.mrdeer.security.permission.MyFilterSecurityInterceptor;
import com.mrdeer.security.validate.EmailValidateFilter;
import com.mrdeer.security.validate.ImageValidateFilter;
import com.mrdeer.security.validate.SmsValidateFilter;
import com.mrdeer.security.validate.VaptchaValidateFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

@Slf4j
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private TokenProperties tokenProperties;

    @Resource
    private AppTokenProperties appTokenProperties;

    @Resource
    private IgnoredUrlsProperties ignoredUrlsProperties;

    @Resource
    private UserDetailsServiceImpl userDetailsService;

    @Resource
    private AuthenticationSuccessHandler successHandler;

    @Resource
    private AuthenticationFailHandler failHandler;

    @Resource
    private RestAccessDeniedHandler accessDeniedHandler;

    @Resource
    private MyFilterSecurityInterceptor myFilterSecurityInterceptor;

    @Resource
    private ImageValidateFilter imageValidateFilter;

    @Resource
    private SmsValidateFilter smsValidateFilter;

    @Resource
    private VaptchaValidateFilter vaptchaValidateFilter;

    @Resource
    private EmailValidateFilter emailValidateFilter;

    @Resource
    private RedisTemplateHelper redisTemplate;

    @Resource
    private SecurityUtil securityUtil;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http.authorizeRequests();
        //除了配置文件忽略路径其它所有请求都需经过认证和授权
        for (String url : ignoredUrlsProperties.getUrls()) {
            registry.antMatchers(url).permitAll();
        }
        registry.and()
                .formLogin()
                .loginPage("/mrdeer/common/needLogin")
                .loginProcessingUrl("/mrdeer/login")
                .permitAll()
                .successHandler(successHandler)
                .failureHandler(failHandler)
                .and()
                .headers()
                .frameOptions()
                .disable()
                .and()
                .logout()
                .permitAll()
                .and()
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .cors()
                .and()
                .csrf()
                .disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .exceptionHandling()
                .accessDeniedHandler(accessDeniedHandler)
                .and()
                .addFilterBefore(imageValidateFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(smsValidateFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(vaptchaValidateFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(emailValidateFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class)
                .addFilter(new JWTAuthenticationFilter(authenticationManager(), tokenProperties, appTokenProperties, redisTemplate, securityUtil));
    }
}
